package thread.test3Volatile;

/**
 * https://www.cnblogs.com/dolphin0520/p/3920373.html
 *
 * 1,原子性 比如i++  和i=a+1就不具备原子性(分三步)
 *
 * 2，可见性：
 *
 * 可见性是指当多个线程访问同一个变量时，一个线程修改了这个变量的值，其他线程能够立即看得到修改的值。
 * 举个简单的例子，看下面这段代码：
 * //线程1执行的代码
 * int i = 0;
 * i = 10;
 //线程2执行的代码
 * j = i;
 * 假若执行线程1的是CPU1，执行线程2的是CPU2。由上面的分析可知，当线程1执行 i =10这句时，会先把i的初始值加载到CPU1的高速缓存中，然后赋值为10，那么在CPU1的高速缓存当中i的值变为10了，却没有立即写入到主存当中。
 * 此时线程2执行 j = i，它会先去主存读取i的值并加载到CPU2的缓存当中，注意此时内存当中i的值还是0，那么就会使得j的值为0，而不是10.
 * 这就是可见性问题，线程1对变量i修改了之后，线程2没有立即看到线程1修改的值
 *
 * 3，有序性：
 * 有序性：即程序执行的顺序按照代码的先后顺序执行。举个简单的例子，看下面这段代码：
 * int i = 0;
 * boolean flag = false;
 * i = 1;                //语句1
 * flag = true;          //语句2
 * 上面代码定义了一个int型变量，定义了一个boolean类型变量，然后分别对两个变量进行赋值操作。
 * 从代码顺序上看，语句1是在语句2前面的，那么JVM在真正执行这段代码的时候会保证语句1一定会在语句2前面执行吗？
 * 不一定，为什么呢？这里可能会发生指令重排序（Instruction Reorder）。
 *
 * 4，指令重排序对单线程没有影响，但对多线程就会有问题，如下：
 *
 * //线程1:
 * context = loadContext();   //语句1
 * inited = true;             //语句2
 *
 //线程2:
 * while(!inited ){
 * sleep()
 * }
 * doSomethingwithconfig(context);
 * 上面代码中，由于语句1和语句2没有数据依赖性，因此可能会被重排序。假如发生了重排序，
 * 在线程1执行过程中先执行语句2，而此是线程2会以为初始化工作已经完成，那么就会跳出while循环，
 * 去执行doSomethingwithconfig(context)方法，而此时context并没有被初始化，就会导致程序出错。
 * 从上面可以看出，指令重排序不会影响单个线程的执行，但是会影响到线程并发执行的正确性。
 * 也就是说，要想并发程序正确地执行，必须要保证原子性、可见性以及有序性。只要有一个没有被保证，
 就有可能会导致程序运行不正确
 *
 *
 * ##################  java内存模型#################################
 *
 *
 * 在前面谈到了一些关于内存模型以及并发编程中可能会出现的一些问题。下面我们来看一下Java内存模型，
 * 研究一下Java内存模型为我们提供了哪些保证以及在java中提供了哪些方法和机制来让我们在进行多线程编程时
 * 能够保证程序执行的正确性。
 * 在Java虚拟机规范中试图定义一种Java内存模型（Java Memory Model，JMM）来屏蔽各个硬件平台
 * 和操作系统的内存访问差异，以实现让Java程序在各种平台下都能达到一致的内存访问效果。
 * 那么Java内存模型规定了哪些东西呢，它定义了程序中变量的访问规则，往大一点说是定义了程序执行的次序。
 * 注意，为了获得较好的执行性能，Java内存模型并没有限制执行引擎使用处理器的寄存器
 * 或者高速缓存来提升指令执行速度，也没有限制编译器对指令进行重排序。也就是说，在java内存模型中，
 * 也会存在缓存一致性问题和指令重排序的问题。
 * Java内存模型规定所有的变量都是存在主存当中（类似于前面说的物理内存），
 * 每个线程都有自己的工作内存（类似于前面的高速缓存）。线程对变量的所有操作都必须在工作内存中进行，
 * 而不能直接对主存进行操作。并且每个线程不能访问其他线程的工作内存。
 * 举个简单的例子：在java中，执行下面这个语句：
 1
 i  = 10;
 * 执行线程必须先在自己的工作线程中对变量i所在的缓存行进行赋值操作，然后再写入主存当中。
 * 而不是直接将数值10写入主存当中。
 * 那么Java语言 本身对 原子性、可见性以及有序性提供了哪些保证呢？
 *
 *
 *
 */
public class VolatileTest1 {
    public volatile int inc = 0;
    public void increase() {
        inc++;
    }

    /**
     * 由本例子可知，volatile 能保证可见性，但并不能保证原子性
     * 另 volatile可保证一定程度的有序性
     */
    public static void main(String[] args) {
        final VolatileTest1 test = new VolatileTest1();
        for(int i=0;i<10;i++){
            new Thread(){
                public void run() {
                    for(int j=0;j<1000;j++)
                        test.increase();
                };
            }.start();
        }

        while(Thread.activeCount()>1)
            Thread.yield();
        System.out.println(test.inc);
    }
}
